﻿#include <Windows.h>
#include <tchar.h>
#include "InputBox.h"
#include "Resource.h"

// 函数声明
static INT_PTR InputBox_DoModal(InputBox*);
static void InputBox_OnCancel(InputBox*);
static void InputBox_OnInitDialog(InputBox*);
static void InputBox_OnOK(InputBox*);
static INT_PTR CALLBACK InputBox_Proc(HWND, UINT, WPARAM, LPARAM);

/**
 * 创建输入窗口，此窗口的返回值类型为整数。
 * @param displayValue  编辑框上显示的默认值
 * @param maxValue      允许输入的最大值
 * @param minValue      允许输入的最小值
 * @param parent        父窗口
 * @param tipText       窗口上的提示文字
 * @return 输入窗口
 */
InputBox* New_InputBox_Int(int displayValue, int maxValue, int minValue, HWND parent, LPCTSTR tipText) {
    // 创建窗口
    InputBox* inputBox = (InputBox*)calloc(1, sizeof(InputBox));

    // 初始化数据
    inputBox->mParent = parent;
    _tcscpy_s(inputBox->mTipText, STRING_BUF_LEN, tipText);
    inputBox->mIntValue = displayValue;
    inputBox->mMaxValue = maxValue;
    inputBox->mMinValue = minValue;

    // 初始化函数
    inputBox->doModal = InputBox_DoModal;

    return inputBox;
}

/**
 * 创建输入窗口，此窗口的返回值类型为字符串。
 * @param maxChars  允许输入的最大字符数
 * @param parent    父窗口
 * @param tipText   窗口上的提示文字
 * @return 输入窗口
 */
InputBox* New_InputBox_String(int maxChars, HWND parent, LPCTSTR tipText) {
    // 创建窗口
    InputBox* inputBox = (InputBox*)calloc(1, sizeof(InputBox));

    // 初始化数据
    inputBox->mParent = parent;
    _tcsncpy_s(inputBox->mTipText, STRING_BUF_LEN, tipText, STRING_BUF_LEN - 1);

    // 初始化函数
    inputBox->doModal = InputBox_DoModal;

    // 设置允许输入的最大字符数
    if (maxChars > 0) {
        SendMessage(GetDlgItem(inputBox->mHandle, IDC_INPUT_BOX_EDIT_VALUE), EM_SETLIMITTEXT, maxChars, 0);
    }

    return inputBox;
}

/**
 * 模态显示输入窗口。
 * @param inputBox  输入窗口
 * @return 为 IDOK 表示用户单击了"确定"按钮，为 IDCANCEL 表示用户单击了"取消"按钮
 */
static INT_PTR InputBox_DoModal(InputBox* inputBox) {
    return DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_INPUT_BOX), inputBox->mParent, InputBox_Proc, (LPARAM)inputBox);
}

/**
 * "取消"按钮的单击响应函数。
 * @param inputBox  输入窗口
 */
static void InputBox_OnCancel(InputBox* inputBox) {
    EndDialog(inputBox->mHandle, IDCANCEL);
}

/**
 * 初始化事件的响应函数。
 * @param inputBox  输入窗口
 */
static void InputBox_OnInitDialog(InputBox* inputBox) {
    TCHAR text[STRING_BUF_LEN] = { 0 };

    // 设置提示文字
    SetDlgItemText(inputBox->mHandle, IDC_INPUT_BOX_TIP_TEXT, inputBox->mTipText);

    // 显示默认值
    if (inputBox->mMinValue != inputBox->mMaxValue) {
        _itot_s(inputBox->mIntValue, text, STRING_BUF_LEN, 10);
        SetDlgItemText(inputBox->mHandle, IDC_INPUT_BOX_EDIT_VALUE, text);
    }
}

/**
 * "确定"按钮的单击响应函数。
 * @param inputBox  输入窗口
 */
static void InputBox_OnOK(InputBox* inputBox) {
    TCHAR text[STRING_BUF_LEN] = { 0 };
    int value = GetDlgItemInt(inputBox->mHandle, IDC_INPUT_BOX_EDIT_VALUE, NULL, TRUE);

    if (inputBox->mMinValue != inputBox->mMaxValue) {
        if (value >= inputBox->mMinValue && value <= inputBox->mMaxValue) {
            inputBox->mIntValue = value;
            EndDialog(inputBox->mHandle, IDOK);
        } else {
            LoadString(NULL, IDS_INPUT_INVALID_VALUE, text, STRING_BUF_LEN);
            MessageBox(inputBox->mHandle, text, _T(" "), MB_ICONWARNING);
            SetFocus(GetDlgItem(inputBox->mHandle, IDC_INPUT_BOX_EDIT_VALUE));
        }
    } else {
        GetDlgItemText(inputBox->mHandle, IDC_INPUT_BOX_EDIT_VALUE, inputBox->mStringValue, STRING_BUF_LEN);
        EndDialog(inputBox->mHandle, IDOK);
    }
}

/**
 * 窗口过程函数。
 * @param window    窗口
 * @param message   事件标识
 * @param wParam    事件相关信息
 * @param lParam    事件相关信息
 * @return 事件在此被处理则返回 TRUE，否则返回 FALSE
 */
static INT_PTR CALLBACK InputBox_Proc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) {
    InputBox* inputBox = (InputBox*)GetWindowLongPtr(window, GWLP_USERDATA);
    WORD id = LOWORD(wParam);

    switch (message) {
        case WM_COMMAND:
            switch (id) {
                case IDCANCEL:
                    InputBox_OnCancel(inputBox);
                    break;
                case IDOK:
                    InputBox_OnOK(inputBox);
                    break;
            }
            return TRUE;
        case WM_INITDIALOG:
            inputBox = (InputBox*)lParam;
            inputBox->mHandle = window;
            SetWindowLongPtr(window, GWLP_USERDATA, (LONG_PTR)inputBox);
            InputBox_OnInitDialog(inputBox);
            return TRUE;
    }
    return FALSE;
}
